package jdbc;

import java.sql.*;

/**
 * Statement执行SQL语句时，我们通过LoginUser案例看到，有可能因为拼接SQL语句导致改变了
 * SQL的语义，出现SQL注入攻击的风险
 *
 * 为了解决这个问题，我们转为使用:PreparedStatement
 * 使用它可以执行预编译SQL语句，将所有待拼接的值先用"?"代替，将SQL语义明确下来发送给数据库
 * 之后再将需要的值传给数据库去执行。
 * 由于是先将预编译SQL发送给数据库，此时数据库会根据预编译SQL生成执行计划(语义定死了)，之后
 * 再传过去的内容数据库仅会将它当作"值"看待，而不会发生语义的变化。
 */
public class JDBCDemo7 {
    public static void main(String[] args) {
        try (
                Connection connection = DBUtil.getConnection();
        ){
            /*
                在预编译SQL中"?"仅能代表"值"
             */
            Statement statement = connection.createStatement();
            String sql = "SELECT username, password,nickname,age "+
                    "FROM userinfo "+
                    "WHERE username= ? "+
                    "AND password= ?";
            //创建预编译SQL语句执行对象时，要先将预编译SQL发送给数据库来确定语义
            //意味着数据库会先根据该SQL生成执行计划，但并没有马上执行，因为还缺少"值"
            PreparedStatement ps = connection.prepareStatement(sql);
            //通过PreparedStatement设置预编译SQL中各个"?"的值
            ps.setString(1,"张三");//针对?对应值的类型调用对应的set方法
            //ps.setString(2,"666666");
            ps.setString(2,"'a' OR '1'='1'");//数据库仅会将它当作密码的"值"看待
            //执行时会将上述对?设置的值传递给数据库
            ResultSet rs =ps.executeQuery();
            if(rs.next()){
                System.out.println("Link Start! "+ rs.getString("nickname")+", 欢迎登录刀剑神域");
            }else {
                System.out.println("登录失败, 用户名或密码不正确");
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }
}
